#include "plugin.h"
#include <stdio.h>
#include <stack>
#include <QtWidgets/QtWidgets>

std::ostream& operator<<(std::ostream& os, const QString& str) {
	   return os<<str.toLocal8Bit().constData();
}


struct Dialog: public QDialog {
	QTextEdit* input;
	QTextEdit* output;
	void convHelper(const QJsonArray& arr, QTextStream& strm, int par) {
		for(const auto& item: arr) {
			if(!item.isObject())
				throwError("Object expected");
			auto obj=item.toObject();

			auto idval=obj.value("id");
			auto id=idval.toInt(-1);
			if(id==-1)
				throwError("Int expected");

			auto acronymval=obj.value("acronym");
			if(!acronymval.isString())
				throwError("String expected");
			auto acronym=acronymval.toString();

			auto nameval=obj.value("name");
			if(!nameval.isString())
				throwError("String expected");
			auto name=nameval.toString();

			auto colorval=obj.value("color_hex_triplet");
			if(!colorval.isString())
				throwError("String expected");
			auto color=colorval.toString();

			strm<<id<<':';
			strm<<par<<':';
			strm<<'#'<<color<<':';
			strm<<acronym<<':';
			strm<<name<<'\n';

			auto childrenval=obj.value("children");
			if(!childrenval.isArray())
				throwError("Array expected");
			auto children=childrenval.toArray();
			convHelper(children, strm, id);
		}
	}

	void conv() {
		try {
			auto dat=input->document()->toPlainText().toLatin1();
			QJsonParseError err;
			auto json=QJsonDocument::fromJson(dat, &err);
			if(err.error!=QJsonParseError::NoError)
				throwError("Failed to parse json: "+err.errorString());
			if(!json.isObject())
				throwError("Object expected");
			auto obj=json.object();
			auto msg=obj.value("msg");
			if(!msg.isArray())
				throwError("Array expected");
			auto arr=msg.toArray();

			QString s;
			QTextStream strm{&s};
			convHelper(arr, strm, 0);
			output->document()->setPlainText(s);
		} catch(const std::exception& e) {
			output->document()->setPlainText(QString{"Failed to convert:\n"}+e.what());
		}
	}
	Dialog(QWidget* par): QDialog{par} {
		auto boxlayout=new QVBoxLayout{this};

		input=new QTextEdit{this};
		boxlayout->addWidget(input, 1);
		input->setAcceptRichText(false);

		auto btn=new QPushButton{"&Convert", this};
		boxlayout->addWidget(btn, 0);
		btn->setDefault(true);
		connect(btn, &QPushButton::clicked, this, &Dialog::conv);

		output=new QTextEdit{this};
		boxlayout->addWidget(output, 1);
		output->setAcceptRichText(false);
		output->setReadOnly(true);
	}
};

struct ConvAllenAnnot final: public GraphReader {
	ConvAllenAnnot(): GraphReader{} { }
	~ConvAllenAnnot() override { }
	void read(Graph gr, QWidget* par) override {
		Dialog dlg{par};
		dlg.exec();
	}
	static GraphReaderInfo info;
	static GraphReader* creater() { return new ConvAllenAnnot{}; }
};

static void simple_load(std::vector<AlgorithmInfo*>& algs, std::vector<GraphReaderInfo*>& readers) {
	readers.push_back(new GraphReaderInfo{"Convert Allen Annotation", 10,
			"Convert annotation file from Allen in JSON format to a list.",
			ConvAllenAnnot::creater});
}

static void simple_unload() {
}
extern "C"
{
	PLUGIN_EXPORT
		FNT_PLUGIN("ConvAllenAnnot", &simple_load, &simple_unload, "Convert Allen Annotation");
}